"""
Web应用主程序
提供数据预处理系统的Web界面
"""

import logging
import os
import json
from flask import Flask, render_template, request, jsonify, send_file, flash, redirect, url_for
from werkzeug.utils import secure_filename
from datetime import datetime
import threading
import uuid

from config.database_config import db_config_manager, DatabaseConfig, DatabaseType, load_config_from_env
from config.ai_config import ai_config_manager, AIModelConfig, AIModelType, load_ai_config_from_env
from src.database.connection_manager import db_manager
from src.database.schema_extractor import schema_extractor
from src.ai.model_interface import ai_model_manager
from src.ai.schema_enhancer import schema_enhancer
from src.export.excel_exporter import excel_exporter
from src.utils.config_storage import config_storage
from src.utils.connection_monitor import connection_monitor
from src.utils.task_storage import task_storage


# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)

# 创建Flask应用
app = Flask(__name__, 
           template_folder='../../templates',
           static_folder='../../static')
app.secret_key = os.urandom(24)

# 配置文件上传
UPLOAD_FOLDER = os.path.abspath('uploads')
EXPORT_FOLDER = os.path.abspath('exports')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['EXPORT_FOLDER'] = EXPORT_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB

# 确保目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(EXPORT_FOLDER, exist_ok=True)

# 任务锁（使用持久化存储）
task_lock = threading.RLock()


@app.route('/')
def index():
    """主页"""
    return render_template('index.html')


@app.route('/database')
def database_config():
    """数据库配置页面"""
    configs = db_config_manager.list_configs()
    return render_template('database_config.html', configs=configs)


@app.route('/ai')
def ai_config():
    """AI配置页面"""
    configs = ai_config_manager.list_configs()
    active_model = ai_config_manager.active_model
    return render_template('ai_config.html', configs=configs, active_model=active_model)


@app.route('/export')
def export_page():
    """导出页面"""
    db_configs = db_config_manager.list_configs()
    ai_configs = ai_config_manager.list_configs()
    return render_template('export.html', db_configs=db_configs, ai_configs=ai_configs)


@app.route('/tasks')
def tasks_page():
    """任务管理页面"""
    return render_template('tasks.html')


# API路由

@app.route('/api/database/configs', methods=['GET'])
def get_database_configs():
    """获取数据库配置列表"""
    try:
        configs = db_config_manager.list_configs()
        config_list = []
        
        for name, config in configs.items():
            config_list.append({
                'name': name,
                'db_type': config.db_type.value,
                'host': config.host,
                'port': config.port,
                'database': config.database,
                'username': config.username
            })
        
        return jsonify({'success': True, 'configs': config_list})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/configs', methods=['POST'])
def add_database_config():
    """添加数据库配置"""
    try:
        data = request.json
        
        config = DatabaseConfig(
            db_type=DatabaseType(data['db_type']),
            host=data['host'],
            port=int(data['port']),
            database=data['database'],
            username=data['username'],
            password=data['password'],
            charset=data.get('charset', 'utf8mb4'),
            connection_timeout=int(data.get('connection_timeout', 30)),
            pool_size=int(data.get('pool_size', 10))
        )
        
        # 验证配置
        if not db_config_manager.validate_config(config):
            return jsonify({'success': False, 'message': '配置验证失败'})
        
        # 添加配置
        db_config_manager.add_config(data['name'], config)
        
        # 保存配置到文件
        config_storage.save_database_configs()
        
        # 立即测试连接
        connection_monitor.force_check(data['name'])
        
        return jsonify({'success': True, 'message': '数据库配置添加成功'})
        
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/test/<config_name>', methods=['POST'])
def test_database_connection(config_name):
    """测试数据库连接"""
    try:
        success = db_manager.test_connection(config_name)
        if success:
            return jsonify({'success': True, 'message': '连接测试成功'})
        else:
            return jsonify({'success': False, 'message': '连接测试失败'})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/schemas/<config_name>', methods=['GET'])
def get_database_schemas(config_name):
    """获取数据库schema列表"""
    try:
        schemas = db_manager.get_schema_names(config_name)
        return jsonify({'success': True, 'schemas': schemas})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/tables/<config_name>', methods=['GET'])
def get_database_tables(config_name):
    """获取数据库表列表"""
    try:
        schema_name = request.args.get('schema')
        tables = db_manager.get_table_names(config_name, schema=schema_name)
        return jsonify({'success': True, 'tables': tables})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/status', methods=['GET'])
def get_database_status():
    """获取所有数据库连接状态"""
    try:
        # 获取连接状态
        status = connection_monitor.get_connection_status()
        summary = connection_monitor.get_connection_summary()
        
        return jsonify({
            'success': True, 
            'status': status,
            'summary': summary
        })
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/status/<config_name>', methods=['GET'])
def get_single_database_status(config_name):
    """获取单个数据库连接状态"""
    try:
        status = connection_monitor.get_connection_status(config_name)
        return jsonify({'success': True, 'status': status})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/database/check/<config_name>', methods=['POST'])
def force_check_connection(config_name):
    """强制检查数据库连接"""
    try:
        result = connection_monitor.force_check(config_name)
        return jsonify({'success': True, 'result': result})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/ai/configs', methods=['GET'])
def get_ai_configs():
    """获取AI配置列表"""
    try:
        configs = ai_config_manager.list_configs()
        config_list = []
        
        for name, config in configs.items():
            config_list.append({
                'name': name,
                'model_type': config.model_type.value,
                'model_name': config.model_name,
                'api_base': config.api_base,
                'max_tokens': config.max_tokens,
                'temperature': config.temperature
            })
        
        return jsonify({'success': True, 'configs': config_list, 'active_model': ai_config_manager.active_model})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/ai/configs', methods=['POST'])
def add_ai_config():
    """添加AI配置"""
    try:
        data = request.json
        
        config = AIModelConfig(
            model_type=AIModelType(data['model_type']),
            model_name=data['model_name'],
            api_key=data.get('api_key'),
            api_base=data.get('api_base'),
            max_tokens=int(data.get('max_tokens', 2048)),
            temperature=float(data.get('temperature', 0.7)),
            local_model_path=data.get('local_model_path'),
            device=data.get('device', 'auto')
        )
        
        # 验证配置
        if not ai_config_manager.validate_config(config):
            return jsonify({'success': False, 'message': '配置验证失败'})
        
        # 添加配置
        ai_config_manager.add_config(data['name'], config)
        
        # 保存配置到文件
        config_storage.save_ai_configs()
        
        return jsonify({'success': True, 'message': 'AI配置添加成功'})
        
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/ai/load/<config_name>', methods=['POST'])
def load_ai_model(config_name):
    """加载AI模型"""
    try:
        success = ai_model_manager.load_model(config_name)
        if success:
            ai_model_manager.set_active_model(config_name)
            return jsonify({'success': True, 'message': 'AI模型加载成功'})
        else:
            return jsonify({'success': False, 'message': 'AI模型加载失败'})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/ollama/models', methods=['GET'])
def get_ollama_models():
    """获取Ollama可用模型列表"""
    try:
        import requests
        
        ollama_url = request.args.get('url', 'http://localhost:11434')
        
        response = requests.get(f"{ollama_url}/api/tags", timeout=5)
        if response.status_code == 200:
            models_data = response.json()
            models = []
            
            for model in models_data.get('models', []):
                models.append({
                    'name': model['name'],
                    'size': model.get('size', 0),
                    'modified': model.get('modified_at', ''),
                    'digest': model.get('digest', '')
                })
            
            return jsonify({'success': True, 'models': models})
        else:
            return jsonify({'success': False, 'message': f'无法连接到Ollama服务: {response.status_code}'})
            
    except requests.exceptions.ConnectionError:
        return jsonify({'success': False, 'message': 'Ollama服务未运行或无法连接'})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/export/start', methods=['POST'])
def start_export():
    """开始导出任务"""
    try:
        data = request.json
        
        # 创建任务ID
        task_id = str(uuid.uuid4())
        
        # 获取参数
        db_config_name = data['db_config']
        ai_config_name = data.get('ai_config')
        export_options = data.get('options', {})
        
        # 创建任务状态
        task_data = {
            'id': task_id,
            'status': 'starting',
            'progress': 0,
            'message': '任务初始化中...',
            'start_time': datetime.now().isoformat(),
            'db_config': db_config_name,
            'ai_config': ai_config_name,
            'options': export_options,
            'result_file': None,
            'error': None
        }
        task_storage.add_task(task_id, task_data)
        
        # 启动后台任务
        thread = threading.Thread(target=_export_task, args=(task_id,))
        thread.daemon = True
        thread.start()
        
        return jsonify({'success': True, 'task_id': task_id})
        
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/api/tasks/<task_id>/status', methods=['GET'])
def get_task_status(task_id):
    """获取任务状态"""
    task = task_storage.get_task(task_id)
    if task:
        return jsonify({'success': True, 'task': task})
    else:
        return jsonify({'success': False, 'message': '任务不存在'})


@app.route('/api/tasks', methods=['GET'])
def get_all_tasks():
    """获取所有任务状态"""
    tasks = task_storage.get_recent_tasks(50)  # 获取最近50个任务
    return jsonify({'success': True, 'tasks': tasks})


@app.route('/api/tasks/recent', methods=['GET'])
def get_recent_tasks():
    """获取最近任务"""
    limit = request.args.get('limit', 10, type=int)
    tasks = task_storage.get_recent_tasks(limit)
    stats = task_storage.get_task_statistics()
    return jsonify({'success': True, 'tasks': tasks, 'statistics': stats})


@app.route('/api/download/<task_id>', methods=['GET'])
def download_result(task_id):
    """下载导出结果"""
    task = task_storage.get_task(task_id)
    if not task:
        return jsonify({'success': False, 'message': '任务不存在'})
    
    if task['status'] != 'completed' or not task['result_file']:
        return jsonify({'success': False, 'message': '文件不可用'})
    
    file_path = task['result_file']
    
    # 检查文件路径是否为绝对路径，如果不是则转换为绝对路径
    if not os.path.isabs(file_path):
        file_path = os.path.abspath(file_path)
    
    if os.path.exists(file_path):
        # 获取文件名用于下载
        filename = os.path.basename(file_path)
        return send_file(file_path, as_attachment=True, download_name=filename)
    else:
        app.logger.error(f"下载文件不存在: {file_path}")
        return jsonify({'success': False, 'message': f'文件不存在: {file_path}'})


def _export_task(task_id: str):
    """导出任务执行函数"""
    try:
        task = task_storage.get_task(task_id)
        if not task:
            return
            
        db_config_name = task['db_config']
        ai_config_name = task['ai_config']
        options = task['options']
        
        # 更新状态：连接数据库
        _update_task_status(task_id, 'connecting', 10, '正在连接数据库...')
        
        # 测试数据库连接
        if not db_manager.test_connection(db_config_name):
            _update_task_status(task_id, 'failed', 0, '数据库连接失败', '无法连接到指定的数据库')
            return
        
        # 更新状态：提取结构
        _update_task_status(task_id, 'extracting', 20, '正在提取数据库结构...')
        
        # 提取数据库结构
        schema = schema_extractor.extract_database_schema(
            db_config_name,
            include_data_info=options.get('include_data_info', True),
            schema_filter=options.get('schema_filter'),
            table_filter=options.get('table_filter'),
            max_workers=3
        )
        
        if not schema:
            _update_task_status(task_id, 'failed', 0, '提取数据库结构失败', '无法获取数据库结构信息')
            return
        
        # 如果启用AI增强
        if ai_config_name and options.get('enable_ai_enhancement', False):
            # 更新状态：加载AI模型
            _update_task_status(task_id, 'loading_ai', 40, '正在加载AI模型...')
            
            # 加载AI模型
            if not ai_model_manager.load_model(ai_config_name):
                _update_task_status(task_id, 'failed', 0, 'AI模型加载失败', '无法加载指定的AI模型')
                return
            
            ai_model_manager.set_active_model(ai_config_name)
            
            # 更新状态：AI增强
            _update_task_status(task_id, 'enhancing', 60, '正在进行AI智能增强...')
            
            # 执行AI增强
            schema = schema_enhancer.enhance_database_schema(
                schema,
                enhance_table_comments=options.get('enhance_table_comments', True),
                enhance_column_comments=options.get('enhance_column_comments', True),
                analyze_relationships=options.get('analyze_relationships', True),
                max_workers=2
            )
        
        # 更新状态：导出Excel
        _update_task_status(task_id, 'exporting', 80, '正在导出Excel文件...')
        
        # 生成输出文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"database_schema_{schema.database_name}_{timestamp}.xlsx"
        output_path = os.path.join(EXPORT_FOLDER, filename)
        
        # 导出Excel
        success = excel_exporter.export_database_schema(
            schema,
            output_path,
            include_summary=options.get('include_summary', True),
            include_relationships=options.get('include_relationships', True),
            include_data_info=options.get('include_data_info', True),
            group_by_schema=options.get('group_by_schema', True),
            ai_enhanced=bool(ai_config_name and options.get('enable_ai_enhancement', False))
        )
        
        if not success:
            _update_task_status(task_id, 'failed', 0, 'Excel导出失败', '无法生成Excel文件')
            return
        
        # 任务完成
        _update_task_status(task_id, 'completed', 100, '导出完成', None, output_path)
        
    except Exception as e:
        _update_task_status(task_id, 'failed', 0, '任务执行失败', str(e))


def _update_task_status(task_id: str, status: str, progress: int, message: str, error: str = None, result_file: str = None):
    """更新任务状态"""
    updates = {
        'status': status,
        'progress': progress,
        'message': message,
        'update_time': datetime.now().isoformat()
    }
    
    if error is not None:
        updates['error'] = error
    if result_file is not None:
        updates['result_file'] = result_file
        
    task_storage.update_task(task_id, updates)


# 初始化配置
def init_app():
    """初始化应用"""
    try:
        # 加载环境变量配置
        load_config_from_env()
        load_ai_config_from_env()
        
        # 加载保存的配置
        config_storage.load_database_configs()
        config_storage.load_ai_configs()
        
        # 启动连接监控
        connection_monitor.start_monitoring()
        
        # 清理过多的历史任务
        task_storage.cleanup_old_tasks(100)
        
        app.logger.info("数据预处理系统启动成功")
        
    except Exception as e:
        app.logger.error(f"初始化失败: {str(e)}")


if __name__ == '__main__':
    init_app()
    app.run(host='0.0.0.0', port=5000, debug=True)